package demo.DtoToVo;

import org.springframework.beans.BeanUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

/**
 * entity -> vo 的转换工具，要转换的 vo 如果是内部类则必须为 static
 *
 * @author xuyong
 * @since 2019-02-13 15:04
 **/
public class ModelConvert {

    /**
     * 自定义 Entity -> VO 的转换逻辑
     *
     * @param entity   Entity
     * @param function 转换逻辑
     * @return VO
     */
    public static <Entity, VO> VO getVO(Entity entity, Function<Entity, VO> function) {
        return function.apply(entity);
    }

    /**
     * 通过 VO 类型从 Entity 获取 VO
     *
     * @param entity Entity
     * @param voType VO 类型
     * @return VO
     */
    public static <Entity, VO> VO getVO(Entity entity, Class voType) {
        return getVO(entity, new CopyProperties<>(voType));
    }

    /**
     * 获取 VO 集合，根据自定义的 Entity -> VO 转换逻辑
     *
     * @param entities Entity 集合
     * @param function 转换逻辑
     * @return VO 集合
     */
    public static <Entity, VO> List<VO> getVOS(List<Entity> entities, Function<Entity, VO> function) {
        List<VO> vos = new ArrayList<>(entities.size());
        iteratorHandle(entities, vos, function);
        return vos;
    }

    /**
     * 获取 VO 集合，根据 VO 类型
     *
     * @param entities Entity 结合
     * @param voType   VO 类型
     * @return VO 集合
     */
    public static <Entity, VO> List<VO> getVOS(List<Entity> entities, Class voType) {
        List<VO> vos = new ArrayList<>(entities.size());
        iteratorHandle(entities, vos, voType);
        return vos;
    }

    /**
     * 迭代填充集合
     *
     * @param entities Entity 集合
     * @param vos      VO 集合
     * @param type     填充条件（Class {@link #getVO(Object, Class)} or Function {@link #getVO(Object, Function)}）
     */
    @SuppressWarnings("unchecked")
    private static <Entity, VO> void iteratorHandle(List<Entity> entities, List<VO> vos, Object type) {
        for (Entity entity : entities) {
            if (type instanceof Class) {
                vos.add(getVO(entity, (Class) type));
            }
            if (type instanceof Function) {
                vos.add(getVO(entity, (Function<Entity, VO>) type));
            }
        }
    }

    /**
     * Entity -> VO 的默认实现，复制属性
     *
     * @param <Entity> Entity
     * @param <VO>     VO
     */
    private static class CopyProperties<Entity, VO> implements Function<Entity, VO> {

        private Class voType;

        CopyProperties(Class voType) {
            this.voType = voType;
        }

        @Override
        public VO apply(Entity entity) {
            try {
                Constructor constructor = voType.getDeclaredConstructors()[0];
                if (!constructor.isAccessible()) {
                    constructor.setAccessible(true);
                }
                @SuppressWarnings("unchecked")
                VO vo = (VO) constructor.newInstance();
                BeanUtils.copyProperties(entity, vo);
                return vo;
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
            return null;
        }

    }

}
